/**
 * 
 */
package com.wgo.precise.server.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;

import remato.domain.common.RequirementSystem;
import remato.domain.common.impl.RequirementSystemImpl;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.HeaderFooter;
import com.lowagie.text.PageSize;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfWriter;
import com.wgo.bpot.common.transport.exception.RematoException;
import com.wgo.bpot.server.persist.Persistent;
import com.wgo.bpot.server.persist.hibernate.HibernatePersistService;
import com.wgo.bpot.server.service.BpotServicesImpl;
import com.wgo.precise.server.export.ExportPrecise;
import com.wgo.precise.server.export.ImportPrecise;
import com.wgo.precise.server.pdf.EndOfPage;
import com.wgo.precise.server.preciseData.RequirementSystemDocument;
import com.wgo.precise.server.wiring.PreciseServiceAccessor;
import com.wgo.precise.service.PreciseServices;

/**
 * 
 * @author Petter L. H. Eide
 * @version $Id: PreciseServicesImpl.java 540 2008-01-09 19:42:31Z petter.eide $
 */
public class PreciseServicesImpl extends BpotServicesImpl implements PreciseServices {

	private static Logger logger = Logger.getLogger(PreciseServicesImpl.class);
	
	private static EndOfPage endOfPage = new EndOfPage();
		
	
	static {
		endOfPage.setEndOfPageText("Precise Requirement System");
	}
	
	public boolean importFromXml(byte[] preciseXmlFile) {
		logger.info("PreciseServicesImpl.importFromXml(File preciseXmlFile) called");
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(preciseXmlFile);
		RequirementSystemDocument requirementSystemDocument = null;
		try {
			requirementSystemDocument = RequirementSystemDocument.Factory.parse(byteArrayInputStream);
			BpotXmlUtil.assertValidDoc(requirementSystemDocument, "Invalid XML document.");
		} catch (XmlException e) {
			throw new RematoException("Unable to import XML at server, invalid XML", e);
		} catch (IOException e) {
			throw new RematoException("Unable to import XML at server, error transfering", e);
		}
        getServiceAccessor().getInitializationService().initialize();
        ImportPrecise importPrecise = new ImportPrecise();
		importPrecise.setPersistService(getPersistService());
		RequirementSystem requirementSystem = importPrecise.readDocument(requirementSystemDocument.getRequirementSystem());
//		RequirementSystem persistedRequirementSystem = (RequirementSystem)getPersistService().findDbRootSystem(getPersistService().getDomainModelConvention().getRootConceptClasses()); // getgetDbInstance(requirementSystem.getClass(), 0);
		RequirementSystem persistedRequirementSystem = (RequirementSystem)getPersistService().findDbRootSystem(RequirementSystem.class); // getgetDbInstance(requirementSystem.getClass(), 0);
		((RequirementSystemImpl)persistedRequirementSystem).setProjectChildren(requirementSystem.getProjectChildren()); // TODO: remove this and convert by reflection... (then it will be possible to use other backend than ejb..(typically modify alogorith in server model converter))
		((RequirementSystemImpl)persistedRequirementSystem).setStakeholders(requirementSystem.getStakeholders());
		((RequirementSystemImpl)persistedRequirementSystem).setPropertySets(requirementSystem.getPropertySets());
        getPersistService().saveOrUpdate(persistedRequirementSystem);
		return true;
	}

	public byte[] exportToXml() {
		logger.info("PreciseServicesImpl: public File exportToXml() called");
		ExportPrecise exportPrecise = new ExportPrecise();
		exportPrecise.setPersistService(getPersistService());
//		RequirementSystemDocument requirementSystemDocument = exportPrecise.createDocument((RequirementSystem)getPersistService().findDbRootSystem(getPersistService().getDomainModelConvention().getRootConceptClass())); // TODO: test this
		RequirementSystemDocument requirementSystemDocument = exportPrecise.createDocument((RequirementSystem)getPersistService().findDbRootSystem(RequirementSystem.class)); // TODO: test this
		BpotXmlUtil.assertValidDoc(requirementSystemDocument, "Invalid document - something persistent data is inconsistent with xml-schema");
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		XmlOptions xmlOption = new XmlOptions();
		xmlOption.setSavePrettyPrint();
		try {
			requirementSystemDocument.save(byteArrayOutputStream,xmlOption);
		} catch (IOException e) {
			throw new RematoException("Unable to create XML-document at server.", e);
		}
		return byteArrayOutputStream.toByteArray();
	}

	public byte[] getPdf(Class<? extends Persistent> conceptType, Serializable identifier) {
		logger.info("PreciseServicesImpl: public File getPdf() called");

		Document doc = new Document();
		ByteArrayOutputStream baosPDF = new ByteArrayOutputStream();
		PdfWriter docWriter = null;
		Throwable throwable = null;
		try {
			docWriter = PdfWriter.getInstance(doc, baosPDF);
			docWriter.setPageEvent(endOfPage);
			doc.addAuthor(this.getClass().getName());
			doc.addCreationDate();
			doc.addProducer();
			doc.addCreator(this.getClass().getName());
			doc.addTitle("Precise Requirement");
			doc.setPageSize(PageSize.LETTER);
			HeaderFooter header = new HeaderFooter(new Phrase(
					"Precise Requirements"), false);
			doc.setHeader(header);
			doc.open();
            getPreciseServiceAccessor().getPdfFactoryRegistry().writeDocument(doc, conceptType.getSimpleName(), (Long)identifier);
		} catch (DocumentException dex) {
			baosPDF.reset();
			throwable = dex;
			throw new RematoException("Error exporting to PDF.",dex) ;
		} catch (Throwable e){
            baosPDF.reset();
            throwable = e;
            throw new RematoException("Error exporting to PDF.",e) ;
		} finally {
			try {
				if (doc != null) {
					doc.close();
				}
				if (docWriter != null) {
					docWriter.close();
				}
			}catch (Throwable e) {
				if (null != throwable) {
					e = throwable;
				}
				throw new RematoException("Could not create PDF at server!", e);
			}
		}
		if (baosPDF.size() < 1) {
			throw new RematoException ("Error exporting PDF. ", new DocumentException("document has " + baosPDF.size() + " bytes"));
		}
		return baosPDF.toByteArray();
	}

	private PreciseServiceAccessor getPreciseServiceAccessor() {
        return (PreciseServiceAccessor)getServiceAccessor();
    }

    @Override
	public HibernatePersistService<Persistent> getPersistService() {
		return (HibernatePersistService<Persistent>)super.getPersistService();
	}

}
